/*
 * @Description: 电影服务层
 * @Author: fhw
 * @Date: 2024-06-15
 */

import { Injectable, UseFilters } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Connection, In, QueryRunner, Repository } from 'typeorm';
import { MovieEntity, } from './entities/movie.entity';
import { CreateMovieDto, UpdateMovieDto, GetMovieDto } from './dto/movie.dto';
import { HttpExceptionFilter } from 'src/common/http-exception.filter';
import { getPagination, throwHttp } from 'src/utlis';
import { isTrue } from 'src/utlis/tools';
import { IdDto } from 'src/common/dto/dto';
import { TagEntity } from '../tags/entities/tag.entity';
import { CategoryEntity } from '../category/entities/category.entity';
import { MoviesEpisodeEntity } from '../movies-episode/entities/movies-episode.entity';
import { AdminUserService } from '../admin-user/admin-user.service';

@Injectable()
export class MovieService {
  constructor(
    @InjectRepository(MovieEntity)
    private readonly movieRepository: Repository<MovieEntity>,
    @InjectRepository(MoviesEpisodeEntity)
    private readonly episodeRepository: Repository<MoviesEpisodeEntity>,
    @InjectRepository(TagEntity)
    private readonly tagRepository: Repository<TagEntity>,
    @InjectRepository(CategoryEntity)
    private readonly categoryRepository: Repository<CategoryEntity>,
    private readonly adminUserService: AdminUserService,
    private readonly connection: Connection,

  ) { }

  /** 创建电影 */
  @UseFilters(new HttpExceptionFilter())
  async createMovie(body: CreateMovieDto) {
    try {
      // 合并现有标签和新标签
      const tags = await this.getOrCreateTags(body.tags, body.lang)

      // 通过类型名称查找类型实体
      const category = await this.categoryRepository.findBy({
        name: In(body.category), // 查找多个类型
      });
      const movie = new MovieEntity();
      movie.name = body.name;
      movie.cover = body.cover;
      movie.free = body.free;
      movie.introduction = body.introduction;
      movie.lang = body.lang;
      movie.tags = tags;
      movie.isRecommend = body.isRecommend;
      movie.playCount = body.playCount;
      movie.rating = body.rating;
      movie.popularity = body.popularity;
      movie.isMustWatch = body.isMustWatch;
      movie.isCurrentlyAiring = body.isCurrentlyAiring;
      movie.isFeatured = body.isFeatured;
      movie.status = body.status;
      movie.category = category || [];

      const result = await this.movieRepository.save(movie);

      if (isTrue(result)) {
        return '电影创建成功';
      }
      return '电影创建失败';
    } catch (error) {
      throwHttp(error.message);
    }
  }

  /** 更新电影 */
  @UseFilters(new HttpExceptionFilter())
  async updateMovie(body: UpdateMovieDto) {
    try {
      const movieInfo = await this.getMovieInfo(body.id);
      if (!isTrue(movieInfo)) {
        throwHttp('电影不存在');
        return;
      }
      // 合并现有标签和新标签
      const tags = await this.getOrCreateTags(body.tags, body.lang)

      // 通过类型名称查找类型实体
      const category = await this.categoryRepository.findBy({
        name: In(body.category), // 查找多个类型
      });
      const { affected } = await this.movieRepository
        .createQueryBuilder()
        .update(MovieEntity)
        .set({
          name: body.name,
          cover: body.cover,
          free: body.free,
          introduction: body.introduction,
          isRecommend: body.isRecommend,
          playCount: body.playCount,
          status: body.status,
          lang: body.lang,
          rating: body.rating,
          popularity: body.popularity,
          isMustWatch: body.isMustWatch,
          isCurrentlyAiring: body.isCurrentlyAiring,
          isFeatured: body.isFeatured,
        })
        .where('id = :id', { id: body.id })
        .execute();
      // 如果电影更新成功，处理多对多关系
      if (affected) {
        // 获取电影实体
        const movie = await this.movieRepository.findOne({
          where: { id: body.id },
          relations: ['tags', 'category'], // 加载现有的标签和分类
        });
        // 更新电影的标签和分类
        movie.tags = tags; // 更新标签
        movie.category = category; // 更新分类
        // 使用 save 方法保存更新后的标签和分类关系
        await this.movieRepository.save(movie);
        return '电影更新成功';
      }
      throwHttp('电影更新失败');
    } catch (error) {
      throwHttp(error.message);
    }
  }

  /** 获取电影 */
  @UseFilters(new HttpExceptionFilter())
  async getMoviePage(params: GetMovieDto) {
    try {
      const { name, lang, free, status, isRecommend } = params;
      const where: GetMovieDto = {
        name,
        status,
        lang,
        free,
        isRecommend
      };
      // 过滤掉为 `undefined` 的属性
      Object.keys(where).forEach(key => where[key] === undefined && delete where[key]);
      // 分页
      const { pageSize, pageNum } = getPagination({
        pageSize: params.pageSize,
        pageNum: params.pageNum,
      });

      const [data, total] = await this.movieRepository.findAndCount({
        where,
        cache: false,
        skip: pageNum * pageSize,  // 跳过的数量
        take: pageSize,  // 每页的数量
        order: { createDate: 'DESC' },  // 排序
        relations: ['tags', 'category'],
      });
      return {
        data: data.map(item => {
          return {
            ...item,
            tags: item?.tags?.map(tag => tag.name),
            category: item?.category?.map(cat => cat.name),
          }
        }),
        total,
        pageSize,
        pageNum: pageNum + 1,
      };
    } catch (error) {
      throwHttp(error.message);
    }
  }

  /** 获取电影详情 */
  @UseFilters(new HttpExceptionFilter())
  async getMovieInfo(id: number) {
    try {
      const data = await this.movieRepository.findOne({
        where: { id },
        cache: true,
        relations: ['tags', 'category'],
      });
      return {
        ...data,
        tags: data?.tags?.map(tag => tag.name),
        category: data?.category?.map(cat => cat.name),
      }
    } catch (error) {
      throwHttp(error.message);
    }
  }

  /** 删除电影 */
  @UseFilters(new HttpExceptionFilter())
  async deleteMovie({ id }: IdDto) {
    try {
      const data = await this.getMovieInfo(id);
      if (!isTrue(data)) {
        throwHttp('电影不存在');
        return;
      }
      await this.movieRepository.softDelete(id);
      return '电影删除成功';
    } catch (error) {
      throwHttp(error.message);
    }
  }
  /** 添加推荐剧集 */
  @UseFilters(new HttpExceptionFilter())
  async addRecommendations(movieId: number, recommendedIds: number[]) {
    try {
      const movie = await this.movieRepository.findOne({
        where: { id: movieId },
        relations: ['recommendedMovies'],
      });
      if (!movie) {
        throwHttp('电影不存在');
      }

      const recommendedMovies = await this.movieRepository.findBy({
        id: In(recommendedIds),
      });

      if (!recommendedMovies.length) {
        throwHttp('推荐的电影不存在');
      }

      movie.recommendedMovies = [
        ...movie.recommendedMovies,
        ...recommendedMovies,
      ];
      await this.movieRepository.save(movie);
      return '推荐剧集添加成功';
    } catch (error) {
      throwHttp(error.message);
    }
  }
  /** 获取推荐剧集 */
  async getRecommendations(movieId: number) {
    const movie = await this.movieRepository.findOne({
      where: { id: movieId },
      relations: ['recommendedMovies', 'recommendedMovies.tags', 'recommendedMovies.category'],
      order: { createDate: 'DESC' },
    });
    if (!movie) {
      throwHttp('电影不存在');
    }
    return movie.recommendedMovies.map(item => {
      return {
        ...item,
        tags: item.tags.map(tag => tag.name),
        category: item.category.map(cat => cat.name),
      }
    });
  }

  /** 删除推荐剧集 */
  async removeRecommendation(movieId: number, recommendedId: number) {
    const movie = await this.movieRepository.findOne({
      where: { id: movieId },
      relations: ['recommendedMovies'],
    });
    if (!movie) {
      throwHttp('电影不存在');
    }
    movie.recommendedMovies = movie.recommendedMovies.filter(
      (rec) => rec.id !== recommendedId,
    );
    await this.movieRepository.save(movie);
    return '推荐剧集删除成功';
  }
  /**
  * 获取或创建标签
  * @param tags 传入的标签名称数组
  * @returns 合并后的标签实体数组
  */
  async getOrCreateTags(tags: string[], lang: string): Promise<TagEntity[]> {
    try {
      // 查找所有现有标签
      const existingTags = await this.tagRepository.find({
        where: { name: In(tags) }, // 查找多个标签
      });

      // 找出哪些标签是不存在的
      const existingTagNames = existingTags.map(tag => tag.name);
      const newTagNames = tags.filter(tag => !existingTagNames.includes(tag));

      // 如果有新标签，添加到数据库
      const newTags = newTagNames.length > 0
        ? await Promise.all(newTagNames.map(name => this.tagRepository.save({ name, lang })))
        : [];

      // 合并现有标签和新标签
      return [...existingTags, ...newTags];
    } catch (error) {
      console.error('创建标签报错:', { error });
      throw error;
    }
  }
  /**
 * 获取或创建标签
 * @param tags 传入的标签名称数组
 * @returns 合并后的标签实体数组
 */
  async getOrCreateCategorys(category: string[], lang: string, createById = 1): Promise<CategoryEntity[]> {
    try {
      // 查找所有现有标签
      const existingTags = await this.categoryRepository.find({
        where: { name: In(category) }, // 查找多个标签
      });

      // 找出哪些标签是不存在的
      const existingTagNames = existingTags.map(tag => tag.name);
      const newTagNames = category.filter(tag => !existingTagNames.includes(tag));

      // 如果有新标签，添加到数据库
      const newTags = newTagNames.length > 0
        ? await Promise.all(newTagNames.map(name => this.categoryRepository.save({ name, lang, createById })))
        : [];

      // 合并现有标签和新标签
      return [...existingTags, ...newTags];
    } catch (error) {
      console.error('创建类型报错:', error);
      throw error;
    }
  }
  /**
 * 创建或更新电影实体
 */
  private async createOrUpdateMovie(movieData: any): Promise<MovieEntity> {
    try {
      const existingMovie = await this.movieRepository.findOneBy({ name: movieData.name });

      const tags = await this.getOrCreateTags(movieData.tags || [], movieData.lang);
      const category = await this.getOrCreateCategorys(movieData.category || [], movieData.lang);
      if (existingMovie) {
        // 更新现有电影
        existingMovie.cover = movieData.cover;
        existingMovie.free = movieData.free;
        existingMovie.introduction = movieData.introduction;
        existingMovie.isRecommend = movieData.isRecommend;
        existingMovie.playCount = movieData.playCount;
        existingMovie.status = movieData.status;
        existingMovie.lang = movieData.lang;
        existingMovie.tags = tags;
        existingMovie.category = category;
        existingMovie.recommendedMovies = movieData.recommendedMovies;
        // 查询推荐的电影是否存在
        return await this.movieRepository.save(existingMovie);
      } else {
        // 创建新电影
        const newMovie = this.movieRepository.create({
          name: movieData.name,
          cover: movieData.cover,
          free: movieData.free,
          introduction: movieData.introduction,
          isRecommend: movieData.isRecommend,
          playCount: movieData.playCount,
          status: movieData.status,
          lang: movieData.lang,
          tags,
          category,
          recommendedMovies: movieData.recommendedMovies,
        });

        return await this.movieRepository.save(newMovie);
      }
    } catch (error) {
      console.error('创建剧情报错:', { movieData, error });
      throw error;
    }
  }

  /**
    * 导入 JSON 数据
    */
  lang = {
    CHINESE: 'zh',
    CHINESE_SIMPLE: 'zhHans',
    ARABIC: 'ar',
    GERMAN: 'de',
    ENGLISH: 'en',
    SPANISH: 'es',
    FRENCH: 'fr',
    BAHASA_INDONESIA: 'in',
    KOREAN: 'ko',
    PORTUGUESE: 'pt',
    THAI: 'th',
  }
  async importJson(jsonData: any[]): Promise<void> {
    try {
      for (const movieData of jsonData) {


        const recommendMovies = await this.processRecommendMovies(movieData,);
        console.log(recommendMovies.map(movie => movie.name));

        // 创建或更新电影实体
        const movieEntity = await this.createOrUpdateMovie({
          name: movieData.name,
          cover: movieData.cover,
          free: movieData.free,
          introduction: movieData.introduction,
          playCount: movieData.chapterCount,
          lang: this.lang[movieData.language] || 'zhHans',
          category: movieData.typeTwoNames,
          tags: movieData.tags,
          recommendedMovies: recommendMovies,
        });
        console.log('正在处理电影:', movieData.name);
        // 处理剧集数据
        await this.processEpisodes(movieData, movieEntity);
      }
    } catch (error) {
      throwHttp('error.message', error.message);
      throw error;
    }

  }
  /**
   * 处理推荐电影
   */
  private async processRecommendMovies(movieData: any,): Promise<MovieEntity[]> {
    const recommendMovies = [];

    for (const recommend of movieData?.bookInfo?.recommends || []) {
      try {
        let recommendEntity = await this.movieRepository.findOne({ where: { name: recommend.name } });

        if (!recommendEntity) {
          const lang = this.lang[recommend.language] || 'zhHans';
          recommendEntity = this.movieRepository.create({
            name: recommend.name,
            cover: recommend.cover,
            free: recommend.free,
            introduction: recommend.introduction,
            playCount: recommend.chapterCount,
            lang,
            category: await this.getOrCreateCategorys(recommend.typeTwoNames, lang),
            tags: await this.getOrCreateTags(recommend.tags || [], lang),
          });
          await this.movieRepository.save(recommendEntity);
        }

        // 只有当推荐电影不重复时，才加入
        if (!recommendMovies.some((movie) => movie.id === recommendEntity.id)) {
          recommendMovies.push(recommendEntity);
        }
      } catch (error) {
        console.error(`推荐电影 "${recommend.name}" 处理失败:`, error);
      }
    }

    return recommendMovies;
  }
  /**
   * 处理剧集数据
   */
  private async processEpisodes(movieData: any, movieEntity: MovieEntity,): Promise<void> {
    for (const episodeData of movieData.bookInfo?.chapterList || []) {
      try {
        let episodeEntity = await this.episodeRepository.findOne({
          where: {
            episodeNumber: episodeData.index,
            name: episodeData.name,
            movies: { id: movieEntity.id },
          },
        });

        if (!episodeEntity) {
          episodeEntity = this.episodeRepository.create({
            name: episodeData.name,
            episodeNumber: episodeData.index,
            mp4: episodeData.mp4,
            cover: episodeData.cover,
            movies: movieEntity,
          });
          await this.episodeRepository.save(episodeEntity);
        }
      } catch (error) {
        console.error(`剧集 "${episodeData.name}" 处理失败:`, error);
      }
    }
  }

}
